package main

import (
    "errors"
    "encoding/json"
    "io/ioutil"
    "net/http"
    //"time"
    "sync"
    //"fmt"
)

type SoftwareTask struct {
    Tid    string `json:"task_id"`
    Sid     string `json:"software_id"`
    State    string `json:"state"`
    InstanceId  string `json:"instance_id"`
}

type SoftwareList struct {
    InstanceId  string `json:"instance_id"`
    SoftList []string `json:"soft_list"`
}

type SoftwareTaskMgr struct {
    lists map[string]*SoftwareList
    tasks map[string]*SoftwareTask
    lock sync.Mutex
}

var gSoftwareTaskMgr *SoftwareTaskMgr = nil
func SoftwareMgrInit() {
    gSoftwareTaskMgr = &SoftwareTaskMgr{}
    gSoftwareTaskMgr.tasks = make(map[string]*SoftwareTask)
    gSoftwareTaskMgr.lists = make(map[string]*SoftwareList)
}

func (mgr *SoftwareTaskMgr) getTasks() []*SoftwareTask {

    mgr.lock.Lock()
    defer mgr.lock.Unlock()
    list := make([]*SoftwareTask, 0)
    for _, c := range mgr.tasks {
        list = append(list, c)
    }
    return list
}

func (mgr *SoftwareTaskMgr) getSoftLists(instance_id string) []string {
    mgr.lock.Lock()
    defer mgr.lock.Unlock()
    for _, c := range mgr.lists {
        if c.InstanceId == instance_id {
            list := make([]string, 0)
            for _, l := range c.SoftList {
                list = append(list, l)
            }
            return list
        }
    }
    return nil
}

func handleSoftwareTaskState(w http.ResponseWriter, req *http.Request) {
    list := gSoftwareTaskMgr.getTasks()
    
    body, _ := json.Marshal(list)
    
    jsonResponse(200, body, w)
}

func getSoftwareTaskHttpApiData(w http.ResponseWriter, req *http.Request) (*SoftwareTask, error) {
    body, err := ioutil.ReadAll(req.Body)
    if err != nil {
        errorResponse(500, false, HttpApiErrCommon, err.Error(), w)
        return nil, err
    }
    
    data := &SoftwareTask{}
    err = json.Unmarshal(body, data)
    if err != nil {
        errorResponse(400, false, HttpApiErrBadRequest, err.Error(), w)
        return nil, err
    }
    if data.Tid == "" || data.Sid == "" || data.InstanceId == "" || data.State == "" {
    	err = errors.New("invalid sid or instance_id or tid or state")
    	errorResponse(400, false, HttpApiErrBadRequest, err.Error(), w)
        return nil, err
    }

    return data, nil
}

func getSoftwareListHttpApiData(w http.ResponseWriter, req *http.Request) (*SoftwareList, error) {
    body, err := ioutil.ReadAll(req.Body)
    if err != nil {
        errorResponse(500, false, HttpApiErrCommon, err.Error(), w)
        return nil, err
    }
    
    data := &SoftwareList{}
    err = json.Unmarshal(body, data)
    if err != nil {
        errorResponse(400, false, HttpApiErrBadRequest, err.Error(), w)
        return nil, err
    }
    if data.InstanceId == "" || data.SoftList == nil {
        err = errors.New("invalid sid or instance_id or tid or state")
        errorResponse(400, false, HttpApiErrBadRequest, err.Error(), w)
        return nil, err
    }

    return data, nil
}

func (mgr *SoftwareTaskMgr) newTaskRecord(info *SoftwareTask) {
    mgr.lock.Lock()
    defer mgr.lock.Unlock()
    
    mgr.tasks[info.Tid] = info
}

func (mgr *SoftwareTaskMgr) newVmSoftRecord(info *SoftwareList) {
    mgr.lock.Lock()
    defer mgr.lock.Unlock()
    mgr.lists[info.InstanceId] = info
}

func (mgr *SoftwareTaskMgr) taskDelete(task_id string) {
    mgr.lock.Lock()
    defer mgr.lock.Unlock()
    
    delete(mgr.tasks, task_id)
}

func handleSoftwareTaskNew(w http.ResponseWriter, req *http.Request) {
    data, err := getSoftwareTaskHttpApiData(w, req)
    if err != nil {
        return
    }

    gSoftwareTaskMgr.newTaskRecord(data)
    
    errorResponse(200, true, 0, "", w)
}

func handleSoftwareListUpload(w http.ResponseWriter, req *http.Request) {
    data, err := getSoftwareListHttpApiData(w, req)
    if err != nil {
        return
    }
    gSoftwareTaskMgr.newVmSoftRecord(data)
    
    errorResponse(200, true, 0, "", w)
}

func handleSoftwareTaskDelete(w http.ResponseWriter, req *http.Request) {
    body, err := ioutil.ReadAll(req.Body)
    if err != nil {
        errorResponse(500, false, HttpApiErrCommon, err.Error(), w)
        return
    }
    var mapData map[string]interface{}
    err = json.Unmarshal(body, &mapData)
    if err != nil {
        errorResponse(400, false, HttpApiErrBadRequest, err.Error(), w)
        return
    }
    if mapData["task_id"] == "" {
    	err = errors.New("invalid tid")
    	errorResponse(400, false, HttpApiErrBadRequest, err.Error(), w)
        return
    }

    gSoftwareTaskMgr.taskDelete(mapData["task_id"].(string))

	errorResponse(200, true, 0, "", w)
}

func handleSoftwareListState(w http.ResponseWriter, req *http.Request) {

    body, err := ioutil.ReadAll(req.Body)
    if err != nil {
        errorResponse(500, false, HttpApiErrCommon, err.Error(), w)
        return
    }
    var mapData map[string]interface{}
    err = json.Unmarshal(body, &mapData)
    if err != nil {
        errorResponse(400, false, HttpApiErrBadRequest, err.Error(), w)
        return
    }
    if mapData["instance_id"] == "" {
        err = errors.New("invalid instance_id")
        errorResponse(400, false, HttpApiErrBadRequest, err.Error(), w)
        return
    }

    list := gSoftwareTaskMgr.getSoftLists(mapData["instance_id"].(string))
    
    ret_body, _ := json.Marshal(list)
    
    jsonResponse(200, ret_body, w)
}